-- StoryValidator.lua - 故事格式验证模块
-- 用于检查故事文件中的格式问题，特别是验证节点引用的有效性

local M = {}

-- 验证故事文件中的节点引用
function M.validate_story_nodes(story_file_path)
    -- 加载故事文件
    local success, story_nodes = pcall(require, story_file_path)
    if not success then
        return {
            valid = false,
            error = "无法加载故事文件: " .. tostring(story_nodes),
            issues = {}
        }
    end
    
    -- 收集所有节点ID
    local node_ids = {}
    for _, node in ipairs(story_nodes) do
        if not node.id then
            return {
                valid = false,
                error = "发现没有ID的节点",
                issues = {}
            }
        end
        node_ids[node.id] = true
    end
    
    -- 检查问题
    local issues = {}
    
    -- 1. 检查每个节点的next引用
    for _, node in ipairs(story_nodes) do
        -- 检查choices中的next引用
        if node.choices then
            for i, choice in ipairs(node.choices) do
                if choice.next then
                    if type(choice.next) == "string" then
                        if not node_ids[choice.next] then
                            table.insert(issues, {
                                type = "无效的节点引用",
                                node_id = node.id,
                                choice_index = i,
                                choice_text = choice.text,
                                target_node = choice.next,
                                message = string.format("节点 '%s' 的第%d个选择 '%s' 引用了不存在的节点 '%s'", 
                                    node.id, i, choice.text or "无文本", choice.next)
                            })
                        end
                    end
                end
            end
        end
        
        -- 检查节点的next属性
        if node.next then
            if type(node.next) == "string" then
                if not node_ids[node.next] then
                    table.insert(issues, {
                        type = "无效的节点引用",
                        node_id = node.id,
                        target_node = node.next,
                        message = string.format("节点 '%s' 的next属性引用了不存在的节点 '%s'", node.id, node.next)
                    })
                end
            end
        end
    end
    
    -- 2. 检查孤立节点（没有其他节点引用的节点）
    local referenced_nodes = {}
    referenced_nodes["intro"] = true  -- intro节点是起始节点，总是被引用
    
    for _, node in ipairs(story_nodes) do
        -- 检查choices中的next引用
        if node.choices then
            for _, choice in ipairs(node.choices) do
                if choice.next and type(choice.next) == "string" then
                    referenced_nodes[choice.next] = true
                end
            end
        end
        
        -- 检查节点的next属性
        if node.next and type(node.next) == "string" then
            referenced_nodes[node.next] = true
        end
    end
    
    -- 找出未被引用的节点
    for _, node in ipairs(story_nodes) do
        if not referenced_nodes[node.id] then
            table.insert(issues, {
                type = "孤立节点",
                node_id = node.id,
                message = string.format("节点 '%s' 没有被其他节点引用", node.id)
            })
        end
    end
    
    -- 3. 检查死胡同节点（没有choices的节点）
    for _, node in ipairs(story_nodes) do
        if not node.choices and not node.next then
            table.insert(issues, {
                type = "死胡同节点",
                node_id = node.id,
                message = string.format("节点 '%s' 没有choices和next属性，是死胡同", node.id)
            })
        end
    end
    
    -- 4. 检查循环引用
    local function check_cycle(node_id, visited, path)
        if visited[node_id] then
            -- 找到循环
            local cycle_start = nil
            for i, id in ipairs(path) do
                if id == node_id then
                    cycle_start = i
                    break
                end
            end
            
            if cycle_start then
                local cycle_path = {}
                for i = cycle_start, #path do
                    table.insert(cycle_path, path[i])
                end
                table.insert(cycle_path, node_id)
                return cycle_path
            end
            return nil
        end
        
        visited[node_id] = true
        table.insert(path, node_id)
        
        -- 查找节点
        local node = nil
        for _, n in ipairs(story_nodes) do
            if n.id == node_id then
                node = n
                break
            end
        end
        
        if not node then
            return nil
        end
        
        -- 检查choices中的next引用
        if node.choices then
            for _, choice in ipairs(node.choices) do
                if choice.next and type(choice.next) == "string" then
                    local cycle = check_cycle(choice.next, visited, path)
                    if cycle then
                        return cycle
                    end
                end
            end
        end
        
        -- 检查节点的next属性
        if node.next and type(node.next) == "string" then
            local cycle = check_cycle(node.next, visited, path)
            if cycle then
                return cycle
            end
        end
        
        table.remove(path)
        return nil
    end
    
    -- 检查从intro节点开始的循环
    local cycle = check_cycle("intro", {}, {})
    if cycle then
        table.insert(issues, {
            type = "循环引用",
            node_id = cycle[1],
            message = string.format("检测到循环引用: %s", table.concat(cycle, " -> "))
        })
    end
    
    -- 返回验证结果
    return {
        valid = #issues == 0,
        node_count = #story_nodes,
        issues = issues
    }
end

-- 打印验证结果
function M.print_validation_result(result)
    if not result.valid then
        if result.error then
            print("验证失败: " .. result.error)
        else
            print("发现 " .. #result.issues .. " 个问题:")
            for i, issue in ipairs(result.issues) do
                print(string.format("%d. [%s] %s", i, issue.type, issue.message))
            end
        end
    else
        print("验证通过! 共检查了 " .. result.node_count .. " 个节点，没有发现问题。")
    end
end

-- 生成验证报告
function M.generate_validation_report(result)
    if not result.valid then
        local report = "# 故事验证报告\n\n"
        report = report .. "验证失败，发现以下问题:\n\n"
        
        if result.error then
            report = report .. "## 错误\n\n" .. result.error .. "\n\n"
        else
            -- 按问题类型分组
            local issues_by_type = {}
            for _, issue in ipairs(result.issues) do
                if not issues_by_type[issue.type] then
                    issues_by_type[issue.type] = {}
                end
                table.insert(issues_by_type[issue.type], issue)
            end
            
            for type, issues in pairs(issues_by_type) do
                report = report .. "## " .. type .. " (" .. #issues .. ")\n\n"
                for _, issue in ipairs(issues) do
                    report = report .. "- " .. issue.message .. "\n"
                end
                report = report .. "\n"
            end
        end
        
        return report
    else
        return "# 故事验证报告\n\n验证通过! 共检查了 " .. result.node_count .. " 个节点，没有发现问题。\n"
    end
end

-- 保存验证报告到文件
function M.save_validation_report(result, file_path)
    local report = M.generate_validation_report(result)
    local file = io.open(file_path, "w")
    if file then
        file:write(report)
        file:close()
        return true
    else
        return false
    end
end

return M